/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/

#include "kstdiostream.h"

void kStdioStream::updateSize() {
	_available = 0;

	if (_istream) {
		std::ios::pos_type p1 = _istream->tellg();
		_istream->seekg(0, std::ios::beg);
		std::ios::pos_type p2 = _istream->tellg();
		_istream->seekg(0, std::ios::end);
		std::ios::pos_type p3 = _istream->tellg();
		_istream->seekg(p1);

		_size = (size_t)(p3-p2);
	} else if (_ostream) {
		std::ios::pos_type p1 = _ostream->tellp();
		_ostream->seekp(0, std::ios::beg);
		std::ios::pos_type p2 = _ostream->tellp();
		_ostream->seekp(0, std::ios::end);
		std::ios::pos_type p3 = _ostream->tellp();
		_ostream->seekp(p1);

		_size = (size_t)(p3-p2);
	}
}
kStdioStream::kStdioStream(std::istream* istream, std::function<void ()> destructor) : kStream(keStream_Read|keStream_Seek|keStream_Measure|keStream_Expand) {
	_istream = istream;
	_ostream = 0;
	_destructor = destructor;

	updateSize();
}
kStdioStream::kStdioStream(std::ostream* ostream, std::function<void ()> destructor) : kStream(keStream_Write|keStream_Seek|keStream_Measure|keStream_Expand) {
	_istream = 0;
	_ostream = ostream;
	_destructor = destructor;
}
kStdioStream::kStdioStream(std::iostream* iostream, std::function<void ()> destructor) : kStream(keStream_Read|keStream_Write|keStream_Seek|keStream_Measure|keStream_Expand) {
	_istream = iostream;
	_ostream = iostream;
	_destructor = destructor;

	updateSize();
}
kStdioStream::~kStdioStream() {
	if (_destructor) {
		_destructor();
	}
}
size_t kStdioStream::write(const kDataView& data) {
	if (!_ostream)
		throw kError(_T("Stream does not support writing!"));

	_ostream->write((const char*)data.ptr, data.size);

	updateSize();

	if (!_ostream->fail()) {
		_writeOffset += data.size;
		return data.size;
	}

	return 0;
}
size_t kStdioStream::read(const kData& data) {
	if (!_istream)
		throw kError(_T("Stream does not support reading!"));

	_istream->read((char*)data.ptr, data.size);

	size_t nb = (size_t)_istream->gcount();
	_readOffset += nb;

	return nb;
}
void kStdioStream::seek(keSeekMode mode, size_t offset) {
	switch (mode) {
	case keSeek_Read:
		_istream->clear();
		_istream->seekg(offset);
		_readOffset = offset;
		break;
	case keSeek_Write:
		_ostream->clear();
		_ostream->seekp(offset);
		_writeOffset = offset;
		break;
	default:
		throw kError(_T("Invalid seek mode!"));
	}
}
void kStdioStream::flush() {
	if (_ostream)
		_ostream->flush();

	updateSize();
}
